UN ESTUDIO SOBRE EL RIESGO DE CONFLAGRACIÓN EN BARCELONA

Máster en Ciencias Actuariales y Financieras
Author
Published

Invalid Date

Introducción

El riesgo de conflagración urbana —la propagación de un incendio entre múltiples edificaciones— representa una de las amenazas más complejas para la solvencia de las entidades aseguradoras de multirriesgo hogar. A diferencia de los siniestros aislados, la conflagración genera una correlación espacial extrema, donde un único evento puede afectar a una acumulación crítica de capital asegurado.

En el marco de Solvencia II y el proceso ORSA, las aseguradoras están obligadas a identificar y cuantificar estas acumulaciones de forma prospectiva. Sin embargo, los métodos tradicionales basados en radios fijos suelen ser insuficientes en entornos urbanos heterogéneos.

Este trabajo tiene como objetivo desarrollar un modelo avanzado de detección de riesgos en la ciudad de Barcelona. Mediante el uso de algoritmos de machine learning espacial (DBSCAN y HDBSCAN), se identifican clusters de exposición real y se propone un score geométrico original que evalúa la peligrosidad tridimensional de la cartera (verticalidad en edificios y proximidad horizontal). El estudio busca transformar datos georreferenciados en una métrica de gestión que permita optimizar el control de acumulaciones y la estrategia de reaseguro de la entidad.

Librerias y Datos

Para la realización del presente trabajo se ha hecho uso de diversas librerías del lenguaje R, orientadas al tratamiento y análisis de datos, así como al análisis espacial.

library(knitr)
library(scales)
library(ggplot2)
library(readr)
library(leaflet)
library(dplyr)
library(tidyverse)
library(sf)
library(dbscan)
set.seed(1234)

Los datos empleados proceden del siguiente conjunto de datos público:

Ajuntament de Barcelona (2024). Llista d’adreces dels edificis de la ciutat de Barcelona [Conjunto de datos]. Oficina Municipal de Dades – Carto BCN. Recuperado de: https://opendata-ajuntament.barcelona.cat/

Con el objetivo de simular el comportamiento de una cartera real de una entidad aseguradora, la base de datos original ha sido modificada mediante la introducción de variables adicionales, permitiendo la generación de una cartera sintética con características coherentes y realistas, adecuada para el desarrollo del ejercicio y el análisis del riesgo de conflagración.

Code
DF_BARCELONA <- read.csv("DF_BARCELONA.csv")
df_polizas <- DF_BARCELONA %>%
  filter(!is.na(codi_illa)) %>%
  mutate(
    densidad_barrio = case_when(
      districte %in% c(2, 6) ~ "Alta",
      districte %in% c(1, 3, 7) ~ "Media",
      TRUE ~ "Baja"
    ),
    lambda_viviendas = recode(
      densidad_barrio,
      "Alta"  = 12,
      "Media" = 8,
      "Baja"  = 4
    ),
    n_viviendas = rpois(n(), lambda_viviendas) + 1
  ) %>%
  uncount(n_viviendas) %>%
  group_by(codi_illa, numpost_i, nom_carrer) %>%
  mutate(
    puertas_por_planta = case_when(
      densidad_barrio == "Alta"  ~ sample(3:4, 1),
      densidad_barrio == "Media" ~ sample(2:3, 1),
      TRUE                       ~ sample(1:2, 1)
    ),
    idx = row_number() - 1,
    planta = (idx %/% puertas_por_planta) + 1,
    puerta = (idx %% puertas_por_planta) + 1
  ) %>%
  ungroup() %>%
  mutate(
    tipo_valor_barrio = case_when(
      nom_barri %in% c(
        "Sarrià", "Sant Gervasi - Galvany",
        "les Tres Torres", "Pedralbes",
        "la Dreta de l'Eixample"
      ) ~ "Alta",
      nom_barri %in% c(
        "Gràcia", "el Raval",
        "Poble-sec", "Sant Antoni", "Sants"
      ) ~ "Media",
      
      TRUE ~ "Baja"
    ),
    suma_asegurada = rlnorm(
      n(),
      meanlog = log(recode(
        tipo_valor_barrio,
        "Alta"  = 350000,
        "Media" = 220000,
        "Baja"  = 140000
      )),
      sdlog = recode(
        tipo_valor_barrio,
        "Alta"  = 0.35,
        "Media" = 0.40,
        "Baja"  = 0.45
      )
    )
  )

A partir de la base de datos original, se ha procedido a la generación de un número variable de viviendas por dirección, en función de la densidad urbana del barrio en el que se ubican. En concreto, el número de viviendas por edificio se simula mediante una distribución de Poisson, cuyo parámetro depende de la densidad urbana del entorno, permitiendo introducir heterogeneidad en el número de pólizas asociadas a cada edificio y reproduciendo de forma razonable la estructura de una cartera real de seguros de hogar.

Asimismo, se ha incorporado una variable de suma asegurada, simulada mediante una distribución log-normal, cuyos parámetros se ajustan en función del tipo de barrio. El uso de esta distribución aleatoria permite capturar la asimetría y la dispersión características del valor asegurado en seguros de hogar, así como reflejar las diferencias de valor inmobiliario existentes en la ciudad de Barcelona.

Las viviendas generadas se han asignado de forma secuencial a plantas y puertas dentro de cada edificio, completando las viviendas disponibles en una planta antes de asignar viviendas a la planta superior.

Finalmente, se selecciona una muestra aleatoria que represente una cartera de polizas de una entidad aseguradora, unas 30mil viviendas, y se eliminan las columnas que no son relevantes para el estudio.

df <- df_polizas %>%
  select(
    x_etrs89,
    y_etrs89,
    codi_illa,
    nom_carrer,
    numpost_i,
    planta,
    puerta,
    suma_asegurada,
    nom_barri
  ) %>%
  filter(
    !is.na(x_etrs89),
    !is.na(y_etrs89)
  ) %>%
  sample_n(20000)
str(df)
tibble [20,000 × 9] (S3: tbl_df/tbl/data.frame)
 $ x_etrs89      : num [1:20000] 431503 431569 428919 428681 431114 ...
 $ y_etrs89      : num [1:20000] 4584881 4581583 4585712 4578235 4581521 ...
 $ codi_illa     : int [1:20000] 25621 99901 83743 22141 12820 92761 27293 50600 99909 80770 ...
 $ nom_carrer    : chr [1:20000] "Còrsega" "Canvis Nous" "Beat Almató" "Gabriel Miró" ...
 $ numpost_i     : int [1:20000] 701 0 99 4 13 31 48 60600 0 34 ...
 $ planta        : num [1:20000] 1 1 2 5 2 5 7 2 1 3 ...
 $ puerta        : num [1:20000] 1 1 1 1 2 1 1 3 1 1 ...
 $ suma_asegurada: num [1:20000] 243420 95449 101324 152861 110039 ...
 $ nom_barri     : chr [1:20000] "el Camp de l'Arpa del Clot" "Sant Pere, Santa Caterina i la Ribera" "el Coll" "la Marina del Prat Vermell" ...
Variable Descripción
x_etrs89 Coordenada X en el sistema de referencia ETRS89 / UTM (metros). Se utiliza para el cálculo de distancias y el clustering espacial.
y_etrs89 Coordenada Y en el sistema de referencia ETRS89 / UTM (metros). Se utiliza para el cálculo de distancias y el clustering espacial.
codi_illa Identificador de la manzana catastral donde se ubica el edificio. Permite agrupar viviendas pertenecientes a un mismo entorno urbano.
nom_carrer Nombre de la vía pública en la que se localiza el edificio. Se emplea para la identificación e interpretación de los clusters.
numpost_i Número de portal del edificio dentro de la vía pública. Identifica la dirección postal del inmueble.
planta Número de planta en la que se sitúa la vivienda dentro del edificio.
puerta Identificador de la puerta dentro de la planta. Permite distinguir viviendas dentro de una misma planta.
suma_asegurada Valor asegurado de la vivienda. Representa la exposición económica al riesgo.
nom_barri Nombre del barrio en el que se ubica la vivienda. Variable contextual utilizada para la interpretación de los resultados.

Clustering geográfico DBSCAN/HDBSCAN

DBSCAN (Density-Based Spatial Clustering of Applications with Noise) es un algoritmo de machine learning no supervisado especialmente adecuado para la identificación de agrupaciones espaciales en datos georreferenciados. A diferencia de otros métodos de clustering, DBSCAN no requiere fijar a priori el número de clusters, sino que los identifica de forma endógena a partir de la densidad local de observaciones. Asimismo, permite controlar explícitamente la escala espacial del análisis mediante el parámetro de radio ε, lo que resulta especialmente conveniente en aplicaciones donde la distancia física entre observaciones tiene una interpretación directa.

Otra ventaja relevante de DBSCAN es su capacidad para identificar observaciones aisladas como ruido, evitando forzar su asignación a un cluster, lo que resulta coherente con la naturaleza del riesgo de acumulación analizado. Estas características hacen de DBSCAN una herramienta idónea para detectar hotspots de riesgo de conflagración en entornos urbanos, donde la proximidad espacial entre pólizas constituye el principal factor de dependencia.

Para el presente ejercicio se aplica el algoritmo DBSCAN con un radio de 30 metros y un número mínimo de tres pólizas para la formación de un cluster. Estos parámetros permiten identificar agrupaciones espaciales relevantes a escala urbana, capturando de forma adecuada posibles focos de acumulación de riesgo de conflagración sin generar clusters excesivamente amplios ni demasiado dispersos.

db <- dbscan(
  x = df[, c("x_etrs89", "y_etrs89")],
  eps = 30,
  minPts = 3
)
df$cluster_id <- db$cluster
max(df$cluster_id)
[1] 2025
mean(df$cluster_id == 0)
[1] 0.46935

El algoritmo ha detectado 2070 clusters, descartando como outlyers o puntos no clusterizables alrededor del 46.85% de las polizas.

df <- df %>% filter(cluster_id > 0)
cluster_sizes <- df %>%
  filter(cluster_id > 0) %>%
  count(cluster_id, name = "n_polizas")
quantile(cluster_sizes$n_polizas, probs = c(0.5, 0.75, 0.9, 0.95, 0.99))
50% 75% 90% 95% 99% 
  4   6   8  11  25 

El análisis del tamaño de los clusters revela que la mayoría de las agrupaciones espaciales identificadas son de pequeña magnitud. La mediana del número de pólizas por cluster es de cuatro, y el 75 % de los clusters contiene 6 pólizas o menos. No obstante, la distribución presenta una cola derecha significativa, con un 1 % de clusters que supera las 25 pólizas, lo que pone de manifiesto la existencia de focos puntuales de elevada acumulación de riesgo, especialmente relevantes para el análisis de conflagración.

A continuación se genera un mapa dianmico con la librería leaflet con unicamente los puntos clusterizados en el que se puede obvservar graficamente la forma y naturaleza de los cúmulos de exposición

Code
df_map <- df %>%
  filter(cluster_id > 0) %>%
  st_as_sf(
    coords = c("x_etrs89", "y_etrs89"),
    crs = 25831 
  ) %>%
  st_transform(4326)
pal <- colorFactor(
  palette = "Set3",
  domain = df_map$cluster_id
)

leaflet(df_map) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(
    lng = 2.1734,   
    lat = 41.3851,  
    zoom = 12
  ) %>%
  addCircleMarkers(
    radius = 3,
    stroke = FALSE,
    fillOpacity = 0.7,
    color = ~pal(cluster_id)
  )

El mapa representa la localización de las pólizas que han sido asignadas a algún cluster espacial, donde el color indica la pertenencia a cada cluster identificado por el algoritmo. Como puede observarse, en la gran mayoría de los casos el algoritmo segmenta adecuadamente las agrupaciones de pólizas. No obstante, en determinadas zonas de elevada densidad urbana se identifican clusters de gran extensión que abarcan áreas amplias, llegando en algunos casos a cubrir barrios completos. Este fenómeno pone de manifiesto una limitación inherente al uso de distancias euclídeas en entornos urbanos densos, donde la estructura viaria y la presencia de calles anchas actúan parcialmente como cortafuegos naturales que no quedan reflejados en una métrica puramente geométrica.

Para matizar este efecto, se aplica el algoritmo HDBSCAN sobre aquellos clusters que superan las diez pólizas, los cuales representan aproximadamente el 8 % del total de agrupaciones identificadas. El objetivo es refinar la segmentación mediante un enfoque basado en densidad jerárquica, permitiendo desarticular macro-clusters.

Code
clusters_grandes <- df %>%
  filter(cluster_id > 0) %>%
  count(cluster_id) %>%
  filter(n > 10) %>%
  pull(cluster_id)

nuevo_id <- max(df$cluster_id) + 1
for (cid in clusters_grandes) {
  idx <- which(df$cluster_id == cid)
  df_sub <- df[idx, ]
  
  hdb <- hdbscan(
    df_sub[, c("x_etrs89", "y_etrs89")], 
    minPts = 3
  )
  sub_clusters <- hdb$cluster
  if (all(sub_clusters == 0)) next
  if (any(sub_clusters == 0)) {
    noise_idx <- which(sub_clusters == 0)
    valid_idx <- which(sub_clusters > 0)
    for (i in noise_idx) {
      dist_to_valid <- sqrt(
        (df_sub$x_etrs89[i] - df_sub$x_etrs89[valid_idx])^2 + 
        (df_sub$y_etrs89[i] - df_sub$y_etrs89[valid_idx])^2
      )
      sub_clusters[i] <- sub_clusters[valid_idx[which.min(dist_to_valid)]]
    }
  }
  for (sc in unique(sub_clusters)) {
    df$cluster_id[idx[sub_clusters == sc]] <- nuevo_id
    nuevo_id <- nuevo_id + 1
  }
}
df %>%
  filter(cluster_id > 0) %>%
  count(cluster_id) %>%
  summarise(
    max_cluster = max(n),
    q99 = quantile(n, 0.99)
  )
# A tibble: 1 × 2
  max_cluster   q99
        <int> <dbl>
1          22    13

Como podemos observar el algoritmo ha reducido los clusteres a menos de 13 polizas para el 99%.

Code
df_map <- df %>%
  filter(cluster_id > 0) %>%
  group_by(cluster_id) %>% 
  mutate(n_polizas = n()) %>% 
  ungroup() %>%
  st_as_sf(
    coords = c("x_etrs89", "y_etrs89"),
    crs = 25831 
  ) %>%
  st_transform(4326)

set.seed(111) 
n_clusters <- length(unique(df_map$cluster_id))
colores_aleatorios <- sample(colors(), n_clusters, replace = TRUE)

pal <- colorFactor(
  palette = colores_aleatorios,
  domain = df_map$cluster_id
)

leaflet(df_map) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(
    lng = 2.1734,   
    lat = 41.3851,  
    zoom = 13 
  ) %>%
  addCircleMarkers(
    radius = 3,
    stroke = FALSE,
    fillOpacity = 0.8,
    color = ~pal(cluster_id),
    label = ~paste0("Cluster: ", cluster_id, " | Pólizas: ", n_polizas)
  )

Score de riesgo de conflagración

Una vez identificadas las agrupaciones espaciales de pólizas mediante técnicas de clustering, el siguiente paso consiste en definir una métrica que permita aproximar el riesgo de conflagración desde un punto de vista geométrico y estructural. A diferencia de enfoques puramente agregados, el riesgo de conflagración urbana no reside en el cluster como una entidad homogénea, sino que emerge de la interacción entre focos estructurales de riesgo —los edificios— y su proximidad espacial.

En consecuencia, el score de riesgo se construye siguiendo una lógica jerárquica en dos niveles:
(i) riesgo estructural dentro de cada edificación (referencia catastral), y
(ii) riesgo de interacción entre edificaciones próximas dentro de un mismo cluster.

Riesgo estructural intra-edificio

Sea \(b\) una referencia catastral (edificio) perteneciente a un cluster espacial \(c\), que contiene \(N_b\) pólizas. El edificio constituye la unidad básica de dependencia estructural, dado que la propagación de un incendio entre viviendas situadas en una misma edificación presenta una probabilidad significativamente superior a la existente entre edificaciones distintas.

Para capturar este riesgo, se define una medida basada en la interacción entre pares de pólizas dentro del edificio. A cada póliza \(i\) se le asigna una coordenada vertical:

\[ z_i = h_0 \cdot \text{planta}_i \]

donde \(h_0\) representa la altura media por planta, fijada en este trabajo en \(h_0 = 3.5\) metros, valor representativo de edificación residencial urbana.

La distancia vertical regularizada entre dos pólizas \(i\) y \(j\) del mismo edificio se define como:

\[ d_{ij}^{(b)} = 1 + \left| z_i - z_j \right| \]

Esta formulación garantiza una distancia mínima estrictamente positiva incluso cuando ambas pólizas se encuentran en la misma planta, representando un escenario de contigüidad máxima.

El riesgo estructural del edificio (b) se define entonces como:

\[ R_b = \sum_{i < j} \frac{1}{d_{ij}^{(b)}} \]

Esta métrica presenta las siguientes propiedades deseables:

  • Si \(N_b = 1\), entonces \(R_b = 0\).

  • Si \(N_b \geq 2\), el riesgo es estrictamente positivo.

  • El riesgo crece de forma monótona con el número de pólizas.

  • La separación en altura reduce, pero no elimina, la dependencia entre exposiciones.

De este modo, se garantiza que la presencia de dos o más pólizas en un mismo edificio sea siempre más riesgosa que la existencia de una única póliza aislada.

Riesgo de interacción entre edificios

Además del riesgo estructural propio de cada edificación, el riesgo de conflagración puede verse amplificado por la proximidad entre edificios distintos, especialmente en entornos urbanos densos. Para capturar este efecto, se introduce un término de interacción entre referencias catastrales dentro de un mismo cluster.

Sea \(d_{bb'}\) la distancia euclídea entre los centroides de dos edificios \(b\) y \(b'\). Se define una función de atenuación espacial:

\[ w_{b b'} = \frac{1}{1 + d_{b b'}^2} \]

que penaliza de forma decreciente la interacción conforme aumenta la distancia entre edificaciones.

Con el fin de distinguir entre el riesgo estructural interno de cada edificio y su contribución potencial como foco de propagación del incendio, se define la masa expuesta del edificio como:

\[ M_b = 1 + R_b \]

El riesgo de interacción entre ambos edificios se define como:

\[ R_{bb'} = M_b \cdot M_{b'} \cdot w_{bb'} \]

Esta formulación garantiza que:

  • Un único edificio no genera riesgo de interacción.
  • Dos edificios próximos generan un riesgo adicional positivo.
  • La interacción aumenta con la concentración interna de pólizas en cada edificio.
  • La distancia actúa como mecanismo de mitigación natural del riesgo.

Definición del score de riesgo del cluster

El score de riesgo de conflagración del cluster \(c\) se define finalmente como la suma del riesgo estructural de los edificios que lo componen y de los términos de interacción entre ellos:

\[ R_c = \sum_{b \in c} R_b + \sum_{b < b'} R_{b b'} \]

Este score cumple propiedades fundamentales para el análisis del riesgo de conflagración:

  • Es monótono respecto al número de pólizas y edificaciones.
  • No presenta diluciones artificiales del riesgo al añadir nuevas exposiciones.
  • Diferencia explícitamente entre riesgo estructural e interacción espacial.

En consecuencia, el indicador propuesto constituye un proxy geométrico robusto de la peligrosidad potencial asociada a escenarios de conflagración urbana, adecuado para su posterior análisis conjunto con la severidad económica y su uso en contextos de gestión de acumulaciones.

Análisis

A continuación se implementa el score de riesgo de conflagración propuesto, incorporando el riesgo estructural intra-edificio y los términos de interacción espacial entre edificaciones dentro de cada cluster.

h0 <- 3.5
df <- df %>%
  mutate(
    z = h0 * planta
  )

calc_Rb <- function(z) {
  n <- length(z)
  if (n < 2) return(0)
  dist_mat <- abs(outer(z, z, "-"))
  dist_mat <- 1 + dist_mat
  sum(1 / dist_mat[upper.tri(dist_mat)])
}
Rb_df <- df %>%
  group_by(cluster_id, codi_illa) %>%
  summarise(
    R_b = calc_Rb(z),
    M_b = 1 + R_b,
    x_b = mean(x_etrs89),
    y_b = mean(y_etrs89),
    .groups = "drop"
  )
calc_R_inter <- function(df_b) {
  n <- nrow(df_b)
  if (n < 2) return(0)
  R <- 0
  for (i in 1:(n - 1)) {
    for (j in (i + 1):n) {
      d <- sqrt(
        (df_b$x_b[i] - df_b$x_b[j])^2 +
        (df_b$y_b[i] - df_b$y_b[j])^2
      )
      w <- 1 / (1 + d^2)
      R <- R + df_b$M_b[i] * df_b$M_b[j] * w
    }
  }
  R
}
cluster_score <- Rb_df %>%
  group_by(cluster_id) %>%
  summarise(
    R_intra = sum(R_b),
    R_inter = calc_R_inter(cur_data()),
    R_c = R_intra + R_inter,
    .groups = "drop"
  )

Dado que el score geométrico constituye un indicador puramente relativo de peligrosidad física, se opta por una clasificación de los clusters en función de percentiles del score. Esta aproximación permite analizar la distribución del capital asegurado a lo largo de distintos niveles de riesgo, evitando la introducción de supuestos adicionales sobre la combinación funcional entre peligrosidad y severidad económica.

exposure_cluster <- df %>%
  group_by(cluster_id) %>%
  summarise(
    exposure = sum(suma_asegurada),
    .groups = "drop"
  )
cluster_risk <- cluster_score %>%
  left_join(exposure_cluster, by = "cluster_id")

cluster_risk <- cluster_risk %>%
  mutate(
    score_percentil = percent_rank(R_c) * 100
  )
cluster_risk <- cluster_risk %>%
  mutate(
    riesgo_clase = case_when(
      score_percentil < 20 ~ "Muy bajo",
      score_percentil < 40 ~ "Bajo",
      score_percentil < 60 ~ "Medio",
      score_percentil < 80 ~ "Alto",
      score_percentil < 95 ~ "Muy alto",
      TRUE ~ "Crítico"
    )
  )
capital_por_clase <- cluster_risk %>%
  group_by(riesgo_clase) %>%
  summarise(
    n_clusters = n(),
    capital_total = sum(exposure),
    capital_medio = mean(exposure),
    .groups = "drop"
  )

Exploración

En la siguiente Figura se representa la relación entre el score geométrico de riesgo y el capital asegurado agregado por cluster. El eje horizontal muestra el valor del score, que actúa como proxy de la peligrosidad geométrica del evento, mientras que el eje vertical recoge la suma asegurada total asociada a cada cluster, como medida de la severidad económica potencial.

Code
ggplot(cluster_risk, aes(x = R_c, y = exposure)) +
  geom_point(alpha = 0.6, size = 2) +
  scale_x_log10() +
  scale_y_log10(
    labels = label_number(big.mark = ".", decimal.mark = ",")
  ) +
  labs(
    x = "Score geométrico de riesgo",
    y = "Capital asegurado por cluster",
    title = "Riesgo geométrico vs capital asegurado por cluster"
  ) +
  theme_minimal()

Como puede observarse, existe una relación positiva entre el capital asegurado agregado por cluster y el score geométrico de riesgo. A medida que aumenta la exposición económica, el score tiende a incrementarse, lo que refleja que los clusters con mayor capital asegurado suelen corresponderse con agrupaciones que concentran un mayor número de pólizas en un espacio reducido. Este comportamiento es consistente con la definición del score, ya que el incremento del capital asegurado suele venir acompañado de una mayor densidad estructural de viviendas aseguradas, capturada por la geometría del cluster.

Code
p90_score <- quantile(cluster_risk$R_c, 0.9)
ggplot(
  cluster_risk %>% filter(R_c >= p90_score),
  aes(x = R_c, y = exposure)
) +
  geom_point(alpha = 0.7, size = 2) +
  scale_x_log10() +
  scale_y_log10(
    labels = function(x) format(x, big.mark = ".", decimal.mark = ",", scientific = FALSE)
  ) +
  labs(
    x = "Score geométrico de riesgo (≥ P90)",
    y = "Capital asegurado por cluster",
    title = "Clusters con score geométrico por encima del percentil 90"
  ) +
  theme_minimal()

La nube resultante pone de manifiesto que una proporción significativa de estos clusters de alto riesgo concentra niveles relevantes de exposición económica, observándose numerosos casos que superan los tres millónes de euros de capital asegurado. Destaca, asimismo, la presencia de un número reducido de clusters que combinan valores extremos del score con acumulaciones económicas elevadas, configurando escenarios prioritarios desde el punto de vista de la gestión del riesgo de conflagración.

A continuación un mapeado del 10% de los clusters con mayor riesgo:

Code
clusters_p90 <- cluster_risk %>%
  filter(R_c >= p90_score) %>%
  pull(cluster_id)

df_map_p90 <- df %>%
  filter(cluster_id %in% clusters_p90) %>%
  group_by(cluster_id) %>%
  mutate(
    n_polizas = n()
  ) %>%
  ungroup() %>%
  st_as_sf(
    coords = c("x_etrs89", "y_etrs89"),
    crs = 25831
  ) %>%
  st_transform(4326)

pal <- colorFactor(
  palette = colors(),
  domain = df_map_p90$cluster_id
)

leaflet(df_map_p90) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(
    lng = 2.1734,
    lat = 41.3851,
    zoom = 13
  ) %>%
  addCircleMarkers(
    radius = 4,
    stroke = FALSE,
    fillOpacity = 0.8,
    color = ~pal(cluster_id),
    label = ~paste0(
      "Cluster: ", cluster_id,
      " | Pólizas: ", n_polizas
    )
  )

Los valores más elevados del score geométrico se asocian a clusters caracterizados por una fuerte concentración estructural de pólizas, tanto dentro de las edificaciones como entre edificios próximos, lo que incrementa de forma significativa el potencial de conflagración.

La siguiente tabla recoge los clusters clasificados como críticos según el score geométrico de riesgo, junto con su capital asegurado agregado. Estos clusters representan escenarios prioritarios desde el punto de vista de la gestión del riesgo de conflagración, al combinar una elevada peligrosidad geométrica con una exposición económica relevante.

Code
cluster_risk %>%
  filter(riesgo_clase == "Crítico") %>%
  select(
    cluster_id,
    R_c,
    score_percentil,
    exposure
  ) %>%
  arrange(desc(R_c)) %>%
  mutate(
    R_c = format(round(R_c, 2), nsmall = 2, big.mark = ".", decimal.mark = ","),
    score_percentil = format(round(score_percentil, 2), nsmall = 2, big.mark = ".", decimal.mark = ","),
    exposure = scales::label_number(
      big.mark = ".", 
      decimal.mark = ",", 
      accuracy = 1
    )(exposure)
  ) %>%
  kable(
    col.names = c("Cluster", "Score geométrico", "Percentil", "Capital asegurado (€)"),
    align = "lrrr",
    caption = "Clusters críticos"
  )
Clusters críticos
Cluster Score geométrico Percentil Capital asegurado (€)
2044 27,32 100,00 3.027.380
2146 22,35 99,96 3.255.513
640 21,01 99,91 1.762.699
2051 18,22 99,87 3.017.451
2313 17,05 99,82 2.734.525
2220 16,54 99,78 1.844.550
2122 14,57 99,73 2.072.205
394 13,54 99,69 1.711.446
857 13,35 99,64 1.264.644
1671 13,18 99,60 1.058.121
2082 12,80 99,55 2.929.415
2067 12,56 99,51 2.799.611
2327 12,56 99,46 3.408.712
90 12,35 99,42 1.403.829
1071 12,06 99,37 1.065.020
2157 12,04 99,33 2.569.133
151 11,59 99,28 1.833.464
492 11,24 99,24 1.599.161
486 10,98 99,19 1.254.939
2121 10,77 99,15 1.851.549
768 10,71 99,11 1.443.148
220 10,38 99,06 1.749.706
732 10,25 99,02 1.235.829
106 9,92 98,97 2.785.543
2036 9,89 98,93 3.063.129
1599 9,72 98,88 1.724.871
237 9,55 98,84 3.198.120
568 9,49 98,79 1.449.922
897 9,47 98,75 1.434.952
2281 9,26 98,70 1.152.526
577 9,24 98,66 1.216.747
93 9,04 98,61 1.278.985
24 9,00 98,57 1.237.639
1207 8,87 98,52 1.989.546
2298 8,79 98,48 3.329.153
316 8,78 98,39 1.879.415
499 8,78 98,39 812.595
782 8,62 98,34 1.366.533
2184 8,54 98,30 2.225.327
157 8,47 98,26 1.710.122
866 8,46 98,21 1.266.433
2237 8,38 98,17 2.247.444
816 8,34 98,12 1.396.204
2225 8,21 98,08 2.418.063
602 7,90 98,03 994.001
2183 7,90 97,99 1.208.587
652 7,89 97,94 1.758.590
1337 7,80 97,90 1.551.856
2140 7,70 97,85 1.212.995
1809 7,61 97,81 933.428
864 7,61 97,76 1.336.276
2198 7,54 97,72 1.330.311
2258 7,49 97,67 1.892.268
2080 7,46 97,63 1.282.803
659 7,40 97,58 1.155.237
786 7,30 97,54 977.382
412 7,26 97,49 1.403.805
2283 7,17 97,45 1.049.254
1087 7,16 97,40 1.932.829
798 7,15 97,36 1.220.067
2210 7,09 97,32 1.545.483
2251 6,97 97,27 1.347.240
2285 6,97 97,23 1.433.208
1560 6,92 97,18 3.869.573
1326 6,79 97,14 2.355.262
162 6,78 97,09 1.170.181
634 6,63 97,05 2.194.970
1331 6,57 97,00 1.833.006
2306 6,37 96,96 1.874.115
302 6,34 96,91 1.225.807
2108 6,30 96,87 1.721.660
92 6,28 96,82 2.031.959
1800 6,25 96,78 969.683
488 6,25 96,73 1.429.284
2119 6,17 96,69 1.359.183
2201 6,15 96,64 1.058.899
104 6,13 96,60 994.961
934 6,12 96,55 1.097.362
1317 6,00 96,47 671.777
1711 6,00 96,47 482.193
2191 5,89 96,42 1.321.779
1045 5,88 96,38 1.506.994
1090 5,85 96,33 1.216.562
889 5,79 96,29 1.693.423
460 5,78 96,24 1.182.511
2240 5,76 96,20 2.167.380
52 5,64 96,15 1.446.291
2314 5,51 96,11 2.668.947
541 5,47 96,06 864.290
2070 5,46 96,02 1.950.241
677 5,42 95,97 1.549.499
2232 5,40 95,93 2.622.680
1429 5,35 95,88 815.742
1245 5,34 95,84 1.080.125
2268 5,34 95,79 865.659
142 5,33 95,62 1.165.914
253 5,33 95,62 661.520
1116 5,33 95,62 595.676
1143 5,33 95,62 610.450
2228 5,31 95,57 1.319.729
254 5,30 95,53 1.429.734
614 5,29 95,48 1.733.482
2081 5,28 95,44 1.870.388
14 5,27 95,39 1.255.459
1378 5,17 95,35 1.448.034
200 5,15 95,30 994.435
140 5,14 95,26 2.532.119
340 5,14 95,21 2.239.629
1283 5,14 95,17 1.542.781
489 5,13 95,12 956.335
485 5,10 95,08 1.481.678

Conclusiones

El presente estudio ha permitido desarrollar y aplicar una metodología avanzada para la identificación y cuantificación del riesgo de conflagración en la ciudad de Barcelona, integrando técnicas de machine learning espacial con una métrica de riesgo estructural y de interacción.

Análisis de la segmentación espacial y el comportamiento del score

La combinación de algoritmos ha demostrado ser una herramienta robusta para la gestión de carteras de seguros. Mientras que el DBSCAN inicial identificó los núcleos de acumulación primaria, el refinamiento mediante HDBSCAN resultó crítico para corregir el fenómeno de los “macro-clusters” en zonas de alta densidad como el Eixample o Ciutat Vella. Esta segmentación jerárquica permite una identificación de focos de riesgo mucho más precisa, evitando que la continuidad urbana diluya la visibilidad de los cúmulos de exposición específicos.

Sobre esta base, la métrica propuesta resuelve una limitación común en el análisis de acumulaciones al no tratar todos los puntos de un cluster por igual. Al diferenciar entre el riesgo estructural intra-edificio (verticalidad y contigüidad) y el riesgo de interacción entre edificios (proximidad horizontal), se valida que el riesgo no es solo una cuestión de volumen de pólizas, sino de su disposición tridimensional. La inclusión de la altura media por planta (\(h_0\)) permite capturar la realidad de la vivienda vertical en Barcelona, donde la probabilidad de propagación ascendente de un incendio es un factor técnico ineludible.

Correlación de exposición e implicaciones para la gestión

El análisis revela una clara correlación positiva entre el score geométrico y el capital asegurado. No obstante, la detección de clusters críticos por encima del percentil 95 pone de manifiesto que el riesgo de conflagración está altamente concentrado. Un número reducido de agrupaciones espaciales representa una amenaza desproporcionada para la solvencia de la entidad, con acumulaciones que superan los tres millones de euros en áreas geográficas muy reducidas.

Desde una perspectiva actuarial y de supervisión, los resultados de este modelo proporcionan un marco técnico para la optimización del reaseguro, permitiendo definir con mayor precisión la prioridad y capacidad de los contratos de exceso de pérdida. Asimismo, facilita la suscripción selectiva mediante el establecimiento de límites de aceptación en zonas donde el score de interacción ya se encuentra en niveles críticos.

Recomendaciones para Futuros Estudios

Para potenciar este modelo, se sugiere la inclusión de variables de vulnerabilidad constructiva (año de construcción, materiales) y la presencia de barreras naturales o viales (anchura de calles) como factores de atenuación en la función de interacción espacial (\(w_{bb'}\)). Así como cruzar la geometría con modelos de probabilidad de incendio.